using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using FarseerGames.FarseerPhysics;
using System.IO;

namespace Kosmos
{
    public class MyGame : Microsoft.Xna.Framework.Game
    {

        #region Fields

        public const int WINDOW_WIDTH = 1280;
        public const int WINDOW_HEIGHT = 1024;

        public const int _max_width = 1280;
        public const int _max_height = 1024;

        public static System.Random random = new Random();

        public static GraphicsDeviceManager graphics;

        float _time_value;
        float _time;
        float _update_time;

        float _scroll;
        static bool _levelIsRunning;
        bool _isGameOver;

        SpriteBatch _spriteBatch;
        ContentManager _content;
        ScreenManager _screenManager;
        //AudioManager _audioManager;
        PhysicsSimulator _simulator;

        CameraEffect _camera;
        List<Level> _levels;
        Level _level;

        #endregion

        #region Getters and Setters


        public ScreenManager ScreenManager
        {
            get { return _screenManager; }
            set { _screenManager = value; }
        }

        public CameraEffect Camera
        {
            get { return _camera; }
            set { _camera = value; }
        }

        public PhysicsSimulator Simulator
        {
            get { return _simulator; }
            set { _simulator = value; }
        }
        /*
        public AudioManager AudioManager
        {
            get { return _audioManager; }
            set { _audioManager = value; }
        }
        */

        public bool isGameOver
        {
            get { return _isGameOver; }
            set { _isGameOver = value; }
        }

        public bool LevelIsRunning
        {
            get { return _levelIsRunning; }
            set { _levelIsRunning = value; }
        }

        public int max_width
        {
            get { return _max_width; }
        }

        public int max_height
        {
            get { return _max_height; }
        }

        public SpriteBatch Sprite
        {
            get { return _spriteBatch; }
        }

        public GraphicsDeviceManager GraphicsDeviceManager
        {
            get { return graphics; }
            set { graphics = value; }
        }

        public List<Level> Levels
        {
            get { return _levels; }
        }

        public Level Level
        {
            get { return _level; }
            set { _level = value; }
        }

        public float UpdateTime
        {
            get { return _update_time; }
            set { _update_time = value; }
        }

        public float TimeValue
        {
            get { return _time_value; }
            set { _time_value = value; }
        }

        #endregion

        #region Initialization

        public MyGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            _content = this.Content;

            TimeValue = 1f;
            _time = 0f;
            _levels = new List<Level>();

            Camera = new CameraEffect(this);
            ScreenManager = new ScreenManager(this);
            //AudioManager = new AudioManager();


        }
        
        
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = _max_width;
            graphics.PreferredBackBufferHeight = _max_height;
            graphics.PreferredBackBufferFormat = SurfaceFormat.Bgr32;
            
            base.IsMouseVisible = true;

            graphics.IsFullScreen = true;
            graphics.ApplyChanges();
            //Player = new Player(this, Level.PlayerBall);

            TexturesPool.Initialize(this);
            
            _scroll = Mouse.GetState().ScrollWheelValue;

            Simulator = new PhysicsSimulator(new Vector2(0, 0));
            Components.Add(_screenManager);

            DrawMainMenu();

            base.Initialize();
        }

        public void CleanLevel()
        {
            _scroll = Mouse.GetState().ScrollWheelValue;
            _levels.Clear();
            Simulator = new PhysicsSimulator(new Vector2(0, 0));
            TimeValue = 1f;
            _time = 0f;
            Camera.Rotation = 0f;
            Camera.Zoom = 1f;
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            /*
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();
            */
            if (_levelIsRunning)
            {
                Simulator.Update((float)gameTime.ElapsedGameTime.Milliseconds * 0.001f * TimeValue);
                base.Update(gameTime);
                GestionActionClavier(gameTime);
                GestionCamera(gameTime);
            }
            else
                base.Update(gameTime);

        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            
            graphics.GraphicsDevice.Clear(new Color(0, 0, 0));

            if (_levelIsRunning)
            {
                _spriteBatch.Begin(
                    SpriteBlendMode.AlphaBlend,
                    SpriteSortMode.Immediate,
                    SaveStateMode.SaveState,
                    Camera.getTransformation(_spriteBatch.GraphicsDevice)
                );

                base.Draw(gameTime);
                _spriteBatch.End();
            }
            else
                base.Draw(gameTime);
        }

        public void DrawLevel(int nbLevel)
        {
            AbstractBall.SpriteBatch = _spriteBatch;
            
            DirectoryInfo levelDir = new DirectoryInfo(Content.RootDirectory + "\\Levels");
            if (Levels.Count() < levelDir.GetFiles().Length)
            {
                foreach (FileInfo file in levelDir.GetFiles())
                {
                    Levels.Add(new Level(this, nbLevel));
                    Console.WriteLine(file);
                }
            }
            Level = Levels[nbLevel - 1];
            Components.Add(Level);
            Camera.InitEffect(new EffectProgressiveZoom(5000, 10f));
            Camera.InitEffect(new EffectProgressiveRotation(5000, (float)(Math.PI * 2.0)));
            
        }

        public void DrawMainMenu()
        {
            ScreenManager.RemoveAllScreens();

            _screenManager.AddScreen(new BackgroundScreen(), null);
            _screenManager.AddScreen(new MainMenuScreen(), null);
        }

        #endregion

        #region Other Methods

        protected void GestionActionClavier(GameTime gameTime)
        {
            if (_time < 100)
            {
                _time += gameTime.ElapsedGameTime.Milliseconds;
                return;
            }
            _time -= 100;

            Keys[] keys = Keyboard.GetState().GetPressedKeys();

            if (keys.Contains(Keys.Up))
            {
                float tmp = (_camera.Zoom) * 1.2f;
                Camera.InitEffect(new EffectProgressiveZoom(500, tmp));
            }
            if (keys.Contains(Keys.Down))
            {
                float tmp = (_camera.Zoom) / 1.1f;
                Camera.InitEffect(new EffectProgressiveZoom(500, tmp));
            }
            if (keys.Contains(Keys.Left))
            {
                _time_value = 0.125f;
            }
            if (keys.Contains(Keys.Right))
            {
                _time_value = 1f;
            }
        }

        protected void GestionCamera(GameTime gameTime)
        {
            if (_scroll != Mouse.GetState().ScrollWheelValue)
            {
                float tmp = ((_scroll <= Mouse.GetState().ScrollWheelValue) ? (_camera.Zoom) * 1.2f : (_camera.Zoom) / 1.1f);
                _camera.InitEffect(new EffectProgressiveZoom(500, tmp));
                //_current.player_ball.diameter += 0.25f;

                _scroll = Mouse.GetState().ScrollWheelValue;
            }

            _camera.Update(gameTime);

            if (_camera.Zoom > 300 / _level.PlayerBall.diameter)
                _camera.Zoom = 300 / _level.PlayerBall.diameter;

            _camera.Focus = _level.PlayerBall.center * _camera.Zoom;
        }

        #endregion
    }
}
